﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 *
 *  This code is provided on an AS IS basis, with no WARRANTIES,
 *  CONDITIONS or GUARANTEES of any kind.
 *  
 **/

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Peter.Common;
using Peter.Common.MainMenu;
using Peter.Common.Tree;

namespace Peter.Ruby
{
   /// <summary>
   /// Represents an open rails project.
   /// </summary>
   public class RailsProject : PeterProject
   {
      private XmlNodeList m_ExpandedNodes;
      private const string PROJECT_FILE = "Peter.Ruby.proj";

      /// <summary>
      /// Initializes a new rails project.
      /// </summary>
      public RailsProject ()
      {
         this.Icon = MainMenuIcon.Ruby;
      }

      /// <summary>
      /// Gets the full path to the project file.
      /// </summary>
      private string ProjectFile
      {
         get
         {
            return string.IsNullOrEmpty (this.ProjectLocation)
               ? string.Empty
               : Path.Combine (ProjectLocation, PROJECT_FILE);
         } 
      }

      /// <summary>
      /// Opens a new rails project from the given path.
      /// </summary>
      /// <param name="projectPath">Path to project.</param>
      public bool Open (string projectPath)
      {
         var ok = false;
         if (Directory.Exists (projectPath))
         {
            this.ProjectLocation = projectPath;
            var baseDir = new DirectoryInfo (projectPath);
            this.ProjectName = baseDir.Name;

            this.m_ExpandedNodes = null;
            if (File.Exists (this.ProjectFile))
            {
               var xDoc = new XmlDocument ();
               xDoc.Load (this.ProjectFile);
               this.m_ExpandedNodes = xDoc.GetElementsByTagName ("expanded");
            }
            this.LoadContent (this, baseDir);
            this.m_ExpandedNodes = null;
            ok = true;
         }
         return ok;
      }

      /// <summary>
      /// Loads the contents of the give directory and all sub directories.
      /// </summary>
      /// <param name="parent">The parent tree item.</param>
      /// <param name="dir">Directory to load from.</param>
      private void LoadContent (EditableTreeViewItem parent, DirectoryInfo dir)
      {
         var directories = dir.GetDirectories ();

         foreach (var dirInfo in directories)
         {
            if (dirInfo.Name.StartsWith (".")) continue;
            var treeItem = CreateTreeItem (parent, dirInfo);
            this.LoadContent (treeItem, dirInfo);
         }

         var files = dir.GetFiles ();
         foreach (var fileInfo in files)
         {
            if (fileInfo.Name.StartsWith (".")) continue;
            CreateTreeItem (parent, fileInfo);
         }
      }

      /// <summary>
      /// Creates a tree item and adds it to the parent.
      /// </summary>
      /// <param name="parent">Parent tree item.</param>
      /// <param name="info">File item to add.</param>
      /// <returns>The newly created tree item.</returns>
      private EditableTreeViewItem CreateTreeItem (EditableTreeViewItem parent, FileSystemInfo info)
      {
         var treeItem = new FileTreeViewItem (parent, info, false)
         {
            Icon = MainMenuIconConverter.GetIconForFile (info)
         };
         parent.Children.Add (treeItem);
         foreach (XmlNode node in this.m_ExpandedNodes)
         {
            if (node.Attributes != null && node.Attributes ["path"].Value == info.FullName)
            {
               treeItem.IsExpanded = true;
               break;
            }
         }
         return treeItem;
      }

      /// <summary>
      /// Occurs when the Peter application is closing.
      /// </summary>
      public override void PeterClosing ()
      {
         if (File.Exists (this.ProjectFile + "_temp"))
            File.Delete (this.ProjectFile + "_temp");

         try
         {
            using (var writer = new XmlTextWriter (this.ProjectFile + "_temp", Encoding.Unicode))
            {
               writer.Indentation = 3;
               writer.Formatting = Formatting.Indented;
               writer.WriteStartDocument ();
               this.SaveStructure (writer);
               writer.WriteEndDocument ();
            }
            File.Delete (this.ProjectFile);
            File.Copy (this.ProjectFile + "_temp", this.ProjectFile);
            File.Delete (this.ProjectFile + "_temp");
         }
         catch (Exception ex)
         {
            Console.Error.WriteLine (ex.Message);
         }
      }

      /// <summary>
      /// Saves the project structure.
      /// </summary>
      /// <param name="writer">Xml output.</param>
      private void SaveStructure (XmlWriter writer)
      {
         writer.WriteStartElement ("structure");
         foreach (var editableTreeViewItem in this.Children.Where (ti => ti.IsExpanded))
         {
            var item = (FileTreeViewItem) editableTreeViewItem;
            SaveExpandedNodes (item, writer);
         }
         writer.WriteEndElement ();
      }

      /// <summary>
      /// Recursivly saves the expanded nodes in the project's structure.
      /// </summary>
      /// <param name="treeItem">Tree item to save.</param>
      /// <param name="writer">Xml output.</param>
      private static void SaveExpandedNodes (FileTreeViewItem treeItem, XmlWriter writer)
      {
         writer.WriteStartElement ("expanded");
         writer.WriteAttributeString ("path", treeItem.File.FullName);
         foreach (var editableTreeViewItem in treeItem.Children.Where (ti => ti.IsExpanded))
         {
            var item = (FileTreeViewItem)editableTreeViewItem;
            SaveExpandedNodes (item, writer);
         }
         writer.WriteEndElement ();
      }
   }
}
